msg_tool\scripts\yuris/
ystd.rs1use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::encoding::*;
6use crate::utils::struct_pack::*;
7use anyhow::Result;
8use msg_tool_macro::*;
9use serde::{Deserialize, Serialize};
10use std::io::{Read, Seek, Write};
11
12#[derive(Debug, StructUnpack, StructPack, Serialize, Deserialize)]
13struct YSTDData {
14 version: u32,
15 num_variables: u32,
16 num_texts: u32,
17}
18
19#[derive(Debug)]
20pub struct YSTDBuilder {}
21
22impl YSTDBuilder {
23 pub const fn new() -> Self {
25 YSTDBuilder {}
26 }
27}
28
29impl ScriptBuilder for YSTDBuilder {
30 fn default_encoding(&self) -> Encoding {
31 Encoding::Cp932
32 }
33
34 fn build_script(
35 &self,
36 buf: Vec<u8>,
37 _filename: &str,
38 encoding: Encoding,
39 _archive_encoding: Encoding,
40 config: &ExtraConfig,
41 _archive: Option<&Box<dyn Script>>,
42 ) -> Result<Box<dyn Script + Send + Sync>> {
43 Ok(Box::new(YSTD::new(MemReader::new(buf), encoding, config)?))
44 }
45
46 fn extensions(&self) -> &'static [&'static str] {
47 &["ybn"]
48 }
49
50 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
51 if buf_len >= 4 && buf.starts_with(b"YSTD") {
52 return Some(20);
53 }
54 None
55 }
56
57 fn script_type(&self) -> &'static ScriptType {
58 &ScriptType::YurisYSTD
59 }
60
61 fn can_create_file(&self) -> bool {
62 true
63 }
64
65 fn create_file<'a>(
66 &'a self,
67 filename: &'a str,
68 writer: Box<dyn WriteSeek + 'a>,
69 encoding: Encoding,
70 file_encoding: Encoding,
71 config: &ExtraConfig,
72 ) -> Result<()> {
73 create_file(
74 filename,
75 writer,
76 encoding,
77 file_encoding,
78 config.custom_yaml,
79 )
80 }
81}
82
83#[derive(Debug)]
84pub struct YSTD {
85 data: YSTDData,
86 custom_yaml: bool,
87}
88
89impl YSTD {
90 pub fn new<T: Read + Seek>(
91 mut reader: T,
92 encoding: Encoding,
93 config: &ExtraConfig,
94 ) -> Result<Self> {
95 let mut sig = [0; 4];
96 reader.read_exact(&mut sig)?;
97 if &sig != b"YSTD" {
98 anyhow::bail!("Unsupported YSTD file.");
99 }
100 let data = YSTDData::unpack(&mut reader, false, encoding, &None)?;
101 Ok(Self {
102 data,
103 custom_yaml: config.custom_yaml,
104 })
105 }
106}
107
108impl Script for YSTD {
109 fn default_output_script_type(&self) -> OutputScriptType {
110 OutputScriptType::Custom
111 }
112
113 fn is_output_supported(&self, output: OutputScriptType) -> bool {
114 matches!(output, OutputScriptType::Custom)
115 }
116
117 fn default_format_type(&self) -> FormatOptions {
118 FormatOptions::None
119 }
120
121 fn custom_output_extension(&self) -> &'static str {
122 if self.custom_yaml { "yaml" } else { "json" }
123 }
124
125 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
126 let s = if self.custom_yaml {
127 serde_yaml_ng::to_string(&self.data)
128 .map_err(|e| anyhow::anyhow!("Failed to serialize to YAML: {}", e))?
129 } else {
130 serde_json::to_string_pretty(&self.data)
131 .map_err(|e| anyhow::anyhow!("Failed to serialize to JSON: {}", e))?
132 };
133 let mut writer = crate::utils::files::write_file(filename)?;
134 let s = encode_string(encoding, &s, false)?;
135 writer.write_all(&s)?;
136 writer.flush()?;
137 Ok(())
138 }
139
140 fn custom_import<'a>(
141 &'a self,
142 custom_filename: &'a str,
143 file: Box<dyn WriteSeek + 'a>,
144 encoding: Encoding,
145 output_encoding: Encoding,
146 ) -> Result<()> {
147 create_file(
148 custom_filename,
149 file,
150 encoding,
151 output_encoding,
152 self.custom_yaml,
153 )
154 }
155}
156
157fn create_file<'a>(
158 custom_filename: &'a str,
159 mut writer: Box<dyn WriteSeek + 'a>,
160 encoding: Encoding,
161 output_encoding: Encoding,
162 yaml: bool,
163) -> Result<()> {
164 let input = crate::utils::files::read_file(custom_filename)?;
165 let s = decode_to_string(output_encoding, &input, true)?;
166 let data: YSTDData = if yaml {
167 serde_yaml_ng::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse YAML: {}", e))?
168 } else {
169 serde_json::from_str(&s).map_err(|e| anyhow::anyhow!("Failed to parse JSON: {}", e))?
170 };
171 writer.write_all(b"YSTD")?;
172 data.pack(&mut writer, false, encoding, &None)?;
173 Ok(())
174}